package com.springboot.manager.util;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.springboot.manager.entity.LogException;
import com.springboot.manager.entity.LogOperate;
import com.springboot.manager.service.ILogExceptionService;
import com.springboot.manager.service.ILogOperateService;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @version v1.0
 * @ProjectName: hlk-microservice-ails
 * @ClassName: LogServiceUtil
 * @Description: TODO(一句话描述该类的功能)
 * @Author: zhangzl
 * @Date: 2021-08-13 13:41
 */
@Component
public class LogServiceUtil {

    @Autowired
    private ILogExceptionService logExceptionService;

    @Autowired
    private ILogOperateService logOperateService;

    /**
     * 换行符
     */
    public static final String NEW_LINE = "\n";

    /**
     * 存储异常日志
     *
     * @param e
     */
    public void saveExceptionLog(Exception e) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String appId = (String) getReqestHeaderInfo(request).get("appid");

        StackTraceElement stackTraceElement = e.getStackTrace()[0];
        String fileName = stackTraceElement.getFileName();
        String className = stackTraceElement.getClassName();
        String methodName = stackTraceElement.getMethodName();
        int lineNum = stackTraceElement.getLineNumber();
        String message = e.getMessage();

        LogException logException = new LogException();
        logException.setFileName(fileName);
        logException.setClassName(className);
        logException.setMethodName(methodName);
        logException.setLineNum(lineNum);
        logException.setMessage(message);

        boolean b = logExceptionService.save(logException);
        System.out.println("===========" + b);

    }

    /**
     * 存储操作日志
     *
     * @param invocation
     */
    public void saveOperateLog(MethodInvocation invocation, StopWatch stopWatch, Object result) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        Class className = invocation.getThis().getClass();
        String methodName = invocation.getMethod().getName();
        StringBuffer url = request.getRequestURL();
        String methodType = request.getMethod();
        String argus = getReqestParam(invocation).toString();
        long time = stopWatch.getTime();

        String totalInfo = StringUtils.join(NEW_LINE, "控制器  ：", className, ".", methodName, NEW_LINE);
        totalInfo = StringUtils.join(totalInfo, "访问URL ：", url, NEW_LINE);
        totalInfo = StringUtils.join(totalInfo, "Method  ：", methodType, NEW_LINE);
        totalInfo = StringUtils.join(totalInfo, "请求参数：", argus, NEW_LINE);
        totalInfo = StringUtils.join(totalInfo, "耗  时  ：", time, "ms", NEW_LINE);
        if (ObjectUtil.isEmpty(result)) {
            totalInfo = StringUtils.join(totalInfo, "返回结果：", result, NEW_LINE);
        } else if (result instanceof ResponseEntity) {
            totalInfo = StringUtils.join(totalInfo, "返回结果：", objectMapper.writeValueAsString(((ResponseEntity) result).getBody()), NEW_LINE);
        } else {
            totalInfo = StringUtils.join(totalInfo, "返回结果：", objectMapper.writeValueAsString(result), NEW_LINE);
        }

        LogOperate logOperate = new LogOperate();
        logOperate.setController(className.toString());
        logOperate.setUrl(url.toString());
        logOperate.setMethodType(methodType);
        logOperate.setArgus(argus);
        logOperate.setTime(new Long(time).intValue());
        logOperate.setResult(JSONObject.toJSONString(result));
        logOperate.setTotalInfo(totalInfo);

        logOperateService.save(logOperate);
    }

    /**
     * @Description 获取请求参数
     * @Version 1.0
     */
    private Map<String, Object> getReqestParam(MethodInvocation invocation) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            Map<String, Object> paramMap = new LinkedHashMap<>();
            Object[] args = invocation.getArguments();
            Method method = invocation.getMethod();
            Parameter[] parameters = method.getParameters();
            if (ArrayUtils.isEmpty(parameters)) {
                return null;
            }
            for (int i = 0; i < parameters.length; i++) {
                if (args[i] instanceof HttpServletRequest) {
                    HttpServletRequest request = (HttpServletRequest) args[i];
                    Enumeration<String> params = request.getParameterNames();
                    while (params.hasMoreElements()) {
                        String key = params.nextElement();
                        paramMap.put(key, request.getParameter(key));
                    }
                } else if (!(args[i] instanceof HttpServletResponse)) {
                    paramMap.put(parameters[i].getName(), objectMapper.writeValueAsString(args[i]));
                }
            }
            return paramMap;
        } catch (JsonProcessingException e) {
            return null;
        }
    }

    /**
     * 获取请求头部信息
     *
     * @param request
     * @return
     */
    private Map<String, Object> getReqestHeaderInfo(HttpServletRequest request) {
        final HashMap<String, Object> hashMap = new HashMap<>();
        final Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = headerNames.nextElement();
            String value = request.getHeader(key);
            hashMap.put(key, value);
        }
        return hashMap;
    }


}
